/**************************************************************************
 * Copyright (C) 2020-2020  Unisound
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 **************************************************************************
 *
 * Description : user_sw_timer.c
 * Author      : liuwenzheng@unisound.com
 * Date        : 2020.04.21
 *
 **************************************************************************/
#include "user_sw_timer.h"
#include <rtthread.h>

#define TAG "sw_timer"

typedef struct usr_timer_s {
  struct rt_timer timer;
  timer_handle_t handle;
  unsigned short magic;
  bool enable;
}usr_timer_t;

typedef struct usr_time_list_s {
  usr_timer_t timers[MAX_TIMER_SUPPORT];
  uni_mutex_t mutex;
  rt_uint8_t flag;
}usr_timer_list_t;

static usr_timer_list_t g_usr_timer;

void user_sw_timer_remove(timer_handle_t handle) {
  unsigned long i;
  usr_timer_t *timer;
  uni_pthread_mutex_lock(g_usr_timer.mutex);
  i = handle & 0xFFFF;
  LOGT(TAG, "handle = 0X%x", handle);
  if (i < MAX_TIMER_SUPPORT) {
    timer = &g_usr_timer.timers[i];
    if (timer->enable && handle == timer->handle) {
      rt_timer_stop(&timer->timer);
      timer->enable = false;
    } else {
      LOGW(TAG, "already remove");
    }
  } else {
    LOGE(TAG, "invalid handle 0x%x", handle);
  }
  uni_pthread_mutex_unlock(g_usr_timer.mutex);
}

timer_handle_t user_sw_timer_add(uint32_t msec, bool single_shot,
                                 usr_sw_timer_callback cb) {
  unsigned long i;
  usr_timer_t *timer;
  char t_name[12];
  rt_tick_t ticks;
  timer_handle_t handle = INVALID_TIMER_HANDLE;
  rt_uint8_t flag = g_usr_timer.flag;
  uni_pthread_mutex_lock(g_usr_timer.mutex);
  if (single_shot) {
    flag |= RT_TIMER_FLAG_ONE_SHOT;
  } else {
    flag |= RT_TIMER_FLAG_PERIODIC;
  }
  if (0 == msec) {
    msec = 1;
  }
  ticks = rt_tick_from_millisecond(msec);
  for (i = 0; i < MAX_TIMER_SUPPORT; i++) {
    timer = &g_usr_timer.timers[i];
    if(! timer->enable) {
      timer->magic++;
      timer->handle = (timer->magic << 16) | i;
      sprintf(t_name, "timer_sw%lu", i);
      rt_timer_init(&timer->timer, t_name, cb, (void *)timer->handle, ticks, flag);
      rt_timer_start(&timer->timer);
      timer->enable = true;
      handle = timer->handle;
      break;
    }
  }
  uni_pthread_mutex_unlock(g_usr_timer.mutex);
  LOGT(TAG, "handle = 0X%x", handle);
  return handle;
}

void user_sw_timer_init(eTIMER_IDX timer_idx, uint32_t particle) {
  uni_memset(&g_usr_timer, 0, sizeof(g_usr_timer));
  uni_pthread_mutex_init(&g_usr_timer.mutex);
  if (eTIMER_SYS == timer_idx) {
    g_usr_timer.flag = RT_TIMER_FLAG_HARD_TIMER;
  } else {
    g_usr_timer.flag = RT_TIMER_FLAG_SOFT_TIMER;
  }
}
